package com.jxin.util.serialize;

import com.jxin.util.serialize.consts.SerializerHandlerEnum;
import com.jxin.util.serialize.err.SerializeExc;
import com.jxin.util.serialize.handler.ISerializeHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.Assert;

import java.util.List;

/**
 * 序列化工具
 * @author Jxin
 * @version 1.0
 * @since 2019/10/23 16:41
 */
@Slf4j
public class SerializeUtil {
    private SerializeUtil(){}

    //**************************************************序列化单对象*****************************************************
    /**
     * 序列化对象
     * 注: byte[] 中, [0]索引位放的是序列化器的类型 type的值
     * @param  obj 被序列化的对象
     * @param  <T> 对象的类型
     * @return 该对象的二进制数组
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serialize(T obj) {
        return serialize(obj, SerializerHandlerEnum.PROTO_STUFF.getType());
    }
    /**
     * 序列化对象
     * 注: byte[] 中, [0]索引位放的是序列化器的类型 type的值
     * @param  obj 被序列化的对象
     * @param  <T> 对象的类型
     * @return 该对象的二进制数组
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serialize(T obj, int type) {
        final ISerializeHandler handler = SerializerHandlerEnum.handlerOfType(type);
        if(handler == null) {
            throw new SerializeExc("non null serializer, type: {} !", type);
        }
        return warpSerializeByteArr(handler.type().byteValue(), handler.serialize(obj));
    }

    /**
     * 指定获取的类型,反序列化二进制数组
     * @param  buffer 二进制数组
     * @param  <T>    对象的类型
     * @return 反序列化出的对象
     * @author Jxin
     */
    public static <T> T deserialize(byte[] buffer, Class<T> clazz) {
        Assert.isTrue(ArrayUtils.isNotEmpty(buffer), "反序列化字节数组不能为null");
        final byte[] serializeByteArr = new byte [buffer.length - 1];
        System.arraycopy(buffer, 1, serializeByteArr, 0, serializeByteArr.length);
        return deserialize(serializeByteArr, buffer[0], clazz);
    }

    /**
     * 反序列化二进制数组
     * 1.根据class反序列出对象
     * @param  buffer 被序列化的 二进制数组
     * @param  type   反序列化执行器的类型
     * @param  clazz  反序列后出的对象的类的字节码对象
     * @param  <T>    对象的类型
     * @return 反序列化出的对象
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    private static <T> T deserialize(byte[] buffer, int type, Class<T> clazz) {
        final ISerializeHandler handler = SerializerHandlerEnum.handlerOfType(type);
        if(handler == null){
            throw new SerializeExc("non null serializer, type: {} !", type);
        }
        return handler.deserialize(buffer, clazz);
    }
    //**************************************************序列化列表*******************************************************
    /**
     * 序列化列表
     * 注: byte[] 中, [0]索引位放的是序列化器的类型 type的值
     * @param  objList 被序列化的列表
     * @param  <T> 列表元素的类型
     * @return 该列表的二进制数组
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serializeList(List<T> objList) {
        return serializeList(objList, SerializerHandlerEnum.PROTO_STUFF.getType());
    }
    /**
     * 序列化列表
     * 注: byte[] 中, [0]索引位放的是序列化器的类型 type的值
     * @param  objList 被序列化的列表
     * @param  <T> 列表元素的类型
     * @return 该列表的二进制数组
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serializeList(List<T> objList, int type) {
        final ISerializeHandler handler = SerializerHandlerEnum.handlerOfType(type);
        if(handler == null) {
            throw new SerializeExc("non null serializer, type: {} !", type);
        }
        return warpSerializeByteArr(handler.type().byteValue(), handler.serializeList(objList));
    }
    /**
     * 指定获取的类型,反序列化二进制数组
     * @param  buffer 二进制数组
     * @param  <T>    列表元素的类型
     * @return 反序列化出的列表
     * @author Jxin
     */
    public static <T> T parseList(byte[] buffer, Class<T> clazz) {
        Assert.isTrue(ArrayUtils.isNotEmpty(buffer), "反序列化字节数组不能为null");
        final byte[] serializeByteArr = new byte [buffer.length - 1];
        System.arraycopy(buffer, 1, serializeByteArr, 0, serializeByteArr.length);
        return deserialize(serializeByteArr, buffer[0], clazz);
    }

    /**
     * 二)
     * 反序列化二进制数组
     * 1.根据class反序列出对象
     * @param  buffer 被序列化的 二进制数组
     * @param  type   反序列化执行器的类型
     * @param  clazz  反序列后出的对象的类的字节码对象
     * @param  <T>    对象的类型
     * @return 反序列化出的对象
     * @author Jxin
     */
    @SuppressWarnings("unchecked")
    private static <T> T parseList(byte[] buffer, int type, Class<T> clazz) {
        final ISerializeHandler handler = SerializerHandlerEnum.handlerOfType(type);
        if(handler == null){
            throw new SerializeExc("non null serializer, type: {} !", type);
        }
        return handler.deserialize(buffer, clazz);
    }
    //**************************************************common*****************************************************
    /**
     * 封装 带有类型的序列化字节数组
     * @param  type             序列化器类型
     * @param  serializeByteArr 序列化字节数组
     * @return 带有类型的序列化字节数组
     */
    private static byte[] warpSerializeByteArr(byte type, byte[] serializeByteArr) {
        final byte[] result = new byte[serializeByteArr.length + 1];
        result[0] = type;
        System.arraycopy(serializeByteArr, 0, result, 1, serializeByteArr.length);
        return result;
    }
}
